/*******************************************************************************
  * 文件：JumpFuction.c
  * 作者：zyz
  * 版本：v1.0.0
  * 日期：2017-08-03
  * 说明：跳转功能
*******************************************************************************/
/* 头文件 *********************************************************************/
#include "JumpFunction.h"
#include "Hardware.h"
#include "CRC.h"

/* 宏定义 *********************************************************************/
// 从引导程序启动标志
// 使用引导程序中断标志
#define u32BOOT_FROM_BOOTLOADER_FLAG    ((U32) 0x8C31A5E9)
#define u32USING_BOOTLOADER_INT_FLAG    ((U32) 0xDE62A407)

/* 类型定义 *******************************************************************/
/* 变量定义 *******************************************************************/
// 从引导程序启动标志
// 使用引导程序中断标志
__no_init volatile static U32 u32BootFromBootloaderFlag @ 0xFFE10;
__no_init volatile static U32 u32UsingBootloaderIntFlag @ 0xFFE14;

/* 函数声明 *******************************************************************/
/* 函数定义 *******************************************************************/

/*******************************************************************************
  * 函数名：UsingBootloaderIntActive
  * 功  能：使用引导程序中断
  * 参  数：无
  * 返回值：结果
  * 说  明：无
*******************************************************************************/
Bool UsingBootloaderIntActive(void)
{
    Bool bReturn = FALSE;

    // 判断标志
    if(u32UsingBootloaderIntFlag == u32USING_BOOTLOADER_INT_FLAG)
    {
        bReturn = TRUE;
    }

    // 返回结果
    return bReturn;
}

/*******************************************************************************
  * 函数名：VerifyImage
  * 功  能：校验程序
  * 参  数：ImageType_te eImage - 程序类型
  * 返回值：结果
  * 说  明：无
*******************************************************************************/
Bool VerifyImage(ImageType_te eImage)
{
    Bool bResult = TRUE;
    U16 u16Crc;
    U32 u32StartAddr;
    U32 u32Length;
    ImageHeader_ts *psHeader;

    // 获取头信息
    if(eImage == eIMAGE_TYPE_BOOTLOADER)
    {
        psHeader = (ImageHeader_ts *)u32BOOTLOADER_HEADER_ADDRESS;
    }
    else if(eImage == eIMAGE_TYPE_APPLICATION)
    {
        psHeader = (ImageHeader_ts *)u32APPLICATION_HEADER_ADDRESS;
    }
    else
    {
        bResult = FALSE;
    }

    // 校验头信息
    if(bResult == TRUE)
    {
        // 初始化校验
        u16Crc = u16IMAGE_CRC_SEED;

        // 计算头信息校验
        u32StartAddr = (U32)psHeader;
        u32Length = (U32)(sizeof(ImageHeader_ts) - sizeof(psHeader->u16ImageHeaderCRC));
        u16Crc = CRC_CalcValue((U8 *)u32StartAddr, u32Length, u16Crc);

        // 判断校验结果
        if(u16Crc != psHeader->u16ImageHeaderCRC)
        {
            bResult = FALSE;
        }
    }

    // 校验程序数据
    if(bResult == TRUE)
    {
        // 初始化校验值
        u16Crc = u16IMAGE_CRC_SEED;

        // 计算头信息之前的程序校验
        u32StartAddr = psHeader->u32ImageAddress;
        u32Length = (U32)psHeader - u32StartAddr;
        u16Crc = CRC_CalcValue((U8 *)u32StartAddr, u32Length, u16Crc);

        // 计算头信息之后的程序校验
        u32StartAddr = (U32)psHeader + sizeof(ImageHeader_ts);
        u32Length = psHeader->u32ImageAddress + psHeader->u32ImageSize - u32StartAddr;
        u16Crc = CRC_CalcValue((U8 *)u32StartAddr, u32Length, u16Crc);

        // 判断校验结果
        if(u16Crc != psHeader->u16ImageDataCRC)
        {
            bResult = FALSE;
        }
    }
    // 返回结果
    return bResult;
}

/*******************************************************************************
  * 函数名：CheckBootAndJump
  * 功  能：检查启动并跳转
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void CheckBootAndJump(void)
{
    ImageHeader_ts *psBootloaderHeader;
    ImageHeader_ts *psApplicationHeader;

    // 获取头信息
    psBootloaderHeader  = (ImageHeader_ts *)u32BOOTLOADER_HEADER_ADDRESS;
    psApplicationHeader = (ImageHeader_ts *)u32APPLICATION_HEADER_ADDRESS;

    // 校验引导程序
    if(VerifyImage(eIMAGE_TYPE_BOOTLOADER) == FALSE)
    {
#ifdef NDEBUG
        while(1);
#endif
    }

    // 从应用程序启动
    // 应用程序校验通过
    // 标识符相同
    if((u32BootFromBootloaderFlag != u32BOOT_FROM_BOOTLOADER_FLAG) &&
       (VerifyImage(eIMAGE_TYPE_APPLICATION) == TRUE) &&
       (strcmp((char const*)psBootloaderHeader->au8ImageId,
               (char const*)psApplicationHeader->au8ImageId) == 0))
    {
        // 清除从引导程序启动标志
        // 清除使用引导程序中断标志
        u32BootFromBootloaderFlag = !u32BOOT_FROM_BOOTLOADER_FLAG;
        u32UsingBootloaderIntFlag = !u32USING_BOOTLOADER_INT_FLAG;

        // 跳转到应用程序（执行应用程序复位中断）
        ApplicationInterruptHandler(0);
    }

    // 清除从引导程序启动标志
    // 设置使用引导程序中断标志
    u32BootFromBootloaderFlag = !u32BOOT_FROM_BOOTLOADER_FLAG;
    u32UsingBootloaderIntFlag = u32USING_BOOTLOADER_INT_FLAG;
}

/*******************************************************************************
  * 函数名：ApplicationInterruptHandler
  * 功  能：应用程序中断处理
  * 参  数：U8 u8Index - 中断索引
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void ApplicationInterruptHandler(U8 u8Index)
{
    InterruptRoutine_tpf *ppfInterruptVectorTable;
    InterruptRoutine_tpf pfInteruptRoutine;
    ImageHeader_ts *psApplicationHeader;

    // 获取应用程序头信息
    psApplicationHeader = (ImageHeader_ts *)u32APPLICATION_HEADER_ADDRESS;

    // 从头信息中获取中断向量表地址
    ppfInterruptVectorTable = (InterruptRoutine_tpf *)psApplicationHeader->u32StartupAddress;

    // 从中断向量表中找到中断函数地址
    pfInteruptRoutine = ppfInterruptVectorTable[u8Index >> 1];

    // 如果中断函数不为空则运行
    if(pfInteruptRoutine != (InterruptRoutine_tpf)NULL)
    {
    	pfInteruptRoutine();
    }
}

/*******************************************************************************
  * 函数名：JumpToBootloader
  * 功  能：跳转到Bootloader
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void JumpToBootloader(void)
{
    // 关闭中断
    Hardware_DisableInterrupt();

    // 设置从引导程序启动标志
    u32BootFromBootloaderFlag = u32BOOT_FROM_BOOTLOADER_FLAG;

    // 系统复位
    Hardware_SystemReset();
}

/*******************************************************************************
  * 函数名：JumpToApplication
  * 功  能：跳转到Application
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void JumpToApplication(void)
{
    // 关闭中断
    Hardware_DisableInterrupt();

    // 清除从引导程序启动标志
    u32BootFromBootloaderFlag = !u32BOOT_FROM_BOOTLOADER_FLAG;

    // 系统复位
    Hardware_SystemReset();
}


/***************************** 文件结束 ***************************************/
